#!/usr/bin/perl
#
# Check email state
#
use strict;
use Counter;
use IsEmail qw(isemail $notemailbecause);
use Getopt::Long;
use POSIX qw(strftime O_RDWR);
use Time::HiRes qw(time);

# program switches
use vars qw($mails $n $state $level $string $write $force $chunk $smtp $userid $oldtoo);
# other vars
use vars qw($count $entry @entries $updates $totalchecktime $totalcheckcount $oldsoskip);
use vars qw($VERBOSE);

$IsEmail::DEBUG = 0;
$n = 100;
$chunk = 20;
$state = "new";
$string = undef;
$VERBOSE = 0;

$write = 0;
$IsEmail::timeout = 15; # set default a bit higher than interactive would like

GetOptions(
	   "count=i" => \$n,
	   "debug" => \$IsEmail::DEBUG,
	   "write" => \$write,
	   "force" => \$force,
	   "oldtoo" => \$oldtoo,
	   "timeout=i" => \$IsEmail::timeout,
	   "smtp", \$smtp,
	   # selection criteria
	   "state=s", \$state,
	   "level=s", \$level,
           "string=s", \$string,
	   "user=i", \$userid,
           "verbose" => \$VERBOSE,
	   );

#tail(1)able output
$| = 1;

$force && warn "Overriding statechange restricts\n";
$write && warn "Writing back\n";

if ($write) {
    $mails = FileTable::open("db/email", O_RDWR);
} else {
    $mails = FileTable::open("db/email");
}
$updates = 0;
# will not work - some entries don't change state when processed
#while ($n > $chunk) {
#    process($chunk);
#    $n -= $chunk;
#}
process($n);
    

# print statistics
print "Table of results\n";
print "================\n";
use vars qw($reason);
for $reason (sort(keys(%IsEmail::answers))) {
    print "$IsEmail::answers{$reason} $reason\n";
}
print "\n\n";
print "$updates updates written\n";
print "$oldsoskip skipped because their usage was OLD\n";
printf "\nAverage check time: %6.2f seconds\n", $totalchecktime / $totalcheckcount if $totalcheckcount > 0;




sub process {
    my $n = shift;

    if ($userid) {
	warn "Getting entries owned by $userid\n";
	@entries = $mails->select("owner = ?  limit $n", $userid);
    } elsif ($string) {
	warn "Getting $n entries containing \"$string\"\n";
	@entries = $mails->select("f_raw like '%$string%' order by rand() limit $n");
    } elsif (defined($level)) {
	if ($state) {
	    warn "Getting $n entries in state $state level $level\n";
	    @entries = $mails->select("state = ? and level = ? order by rand() limit $n", $state, $level);
	} else {
	    warn "Getting $n entries in level $level\n";
	    @entries = $mails->select("level = ? order by rand() limit $n", $level);
	}
    } else {
	warn "Getting $n entries in state $state\n";
	@entries = $mails->select("state = ? order by rand() limit $n", $state);
    }
    warn "Got ", @entries + 0, " entries\n";
    for $entry (@entries) {
	if ($entry->{usage} eq "old" && !$oldtoo) {
	    $VERBOSE && print $entry->key(), ": usage old - not checked\n";
	    ++ $oldsoskip;
	    next;
	}
	my $starttime = time();

	my ($res, $level, $why);
	my $addr = $entry->key();
	++ $count;
	if ($smtp) {
	    ($res, $level, $why) = IsEmail::checkemail($addr);
	} else {
	    ($res, $level, $why) = IsEmail::checkemail($addr, "nosmtp");
	}
	my $elapsed = time() - $starttime;
	$IsEmail::DEBUG && warn sprintf("Checktime: %6.2f\n", $elapsed);
	$totalchecktime += $elapsed;
	++ $totalcheckcount;
	my $oldstate = $entry->{state};
	my $olderror = $entry->{error};
	if (!$res) { # BAD
	    $VERBOSE && print "$addr: BAD $level $why\n";
	    $entry->setstate("bad", $level, $why, $force);
	} elsif ($res == 2) { # temp failure
	    $VERBOSE && print "$addr: TEMP $level $why\n";
	    $entry->setstate("tempfail", $level, $why, $force);
	} else { # 1 - OK
	    $VERBOSE && print "$addr: OK $level $why\n";
	    if ($Counter::Email::lmap{$entry->{level}}
		<= $Counter::Email::lmap{$level} || $force) {
		if ($entry->{state} eq "bad") {
		    # HOLLER - change from Bad to something OK
		    print <<EoF;
==============================
| $addr: CHANGE from BAD($$entry{level}) to OK($level)
| Old error: $$entry{error}
| SMTP flag: $smtp
=============================
EoF
                }
		$entry->setstate("ok", $level, "", $force);
	    } else {
		$IsEmail::DEBUG && warn "Skipping - level $$entry{level} higher than $level\n";
	    }
	}
	print $entry->textform() if $IsEmail::DEBUG;
	if ($force || $write
	    && ($oldstate ne $entry->{state}
		|| $olderror ne $entry->{error})) {
	    $IsEmail::DEBUG && warn "Storing\n";
	    $entry->store();
	    ++ $updates;
	}
    }
}
